﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Threading;
using JigLibX.Physics;
using JigLibX.Collision;
using JigLibX.Geometry;
using Microsoft.Xna.Framework.Input.Touch;
using Services;
using Utilities;

namespace WAS.Logic
{
    using Geometry = Body;
    using Nuke = Projectile;
    using NukeData = ProjectileData;

    /// <summary>
    /// Lo stato contiene la descrizione della scena e pochi servizi
    /// utili. Lo stato per ora é dato da:
    /// * nave del giocatore
    /// * navi nemiche
    /// * laser in volo (ogni laser ha una faction con cui sappiamo se
    ///   é del giocatore o del nemico)
    /// * missili nucleari in volo (hanno anche loro il campo faction)
    /// * timer di slow-motion
    /// * bonus correntemente attivi
    /// </summary>
    /// <remarks>
    /// !MOLTO IMPORTANTE!
    /// Non usiamo references da nessuna parte, per avere la massima velocitá
    /// di allocazione/deallocazione. Quindi manteniamo un pool di struct che
    /// sono i dati di ogni oggetto. Ship contiene solo un intero: l'indice della
    /// nave nel pool di navi memorizzate; le proprietá di Ship sono solo dei
    /// proxy per andare a modificare direttamente i dati della nave vera e
    /// propria (vedere definizione di Ship e ShipData).
    /// 
    /// I dati di un oggetto, ad esempio delle navi, sono mantenute dalla classe
    /// statica StructAllocator[ShipData]; tale classe ha i metodi New e Delete
    /// per riservarci (o liberare) un campo all'interno del pool.
    /// </remarks>
    public class State
    {
        public ArrayList<Ship> enemies;
        public ArrayList<Ship> bosses;
        public ArrayList<Bonus> bonuses;
        public ArrayList<Asteroid> asteroids;
        public ArrayList<ShockWave> shockwaves;

        static public readonly float MAX_SLOW_MOTION_TIME = 10.0f;
        static public readonly float MAX_ALLERT_MOTION_TIME = 2.0f;
        static public readonly float MAX_BUZZ_MOTION_TIME = 5.0f;
        static public readonly float X_ANIMATION_DURATION = 0.5f;

        public float totalgametime = 0;

        public float slow_motion_timer = 0.0f;
        public float allert_motion_timer = 0.0f;
        public float buzz_motion_timer = 0.0f;

        public int num_of_asteroids_hit = 0;
        public int level;
        public  const float TIME_FOR_LEVEL = 30.0f;
        public float time_to_next_level;        
        public float time_to_add_or_remove = 0.0f;
               

        public void RemoveShockWaveAt(int index)
        {
            var s = shockwaves[index];
            StructAllocator<ShockWaveData>.Delete(s.self);
            shockwaves.RemoveAt(index);
        }
        internal void RemoveShipAt(int index)
        {
            var p = enemies[index];
            StructAllocator<ShipData>.Delete(p.self);
            enemies.RemoveAt(index);
        }

        internal void RemoveBossAt(int index)
        {
            var p = bosses[index];
            StructAllocator<ShipData>.Delete(p.self);

            bosses.RemoveAt(index);
        }

        internal void RemoveBonusAt(int index)
        {
            var p = bonuses[index];
            StructAllocator<BonusData>.Delete(p.self);
            bonuses.RemoveAt(index);
        }

        internal void RemoveAsteroidAt(int index)
        {
            var p = asteroids[index];
            StructAllocator<AsteroidData>.Delete(p.self);
            asteroids.RemoveAt(index);
        }

        public float slow_motion
        {
            get
            {
                return MathHelper.SmoothStep(1.0f, 0.01f, slow_motion_timer / State.MAX_SLOW_MOTION_TIME);
            }
        }
        public float allert_motion
        {
            get
            {
                return MathHelper.SmoothStep(1.0f, 0.01f, allert_motion_timer / State.MAX_ALLERT_MOTION_TIME); 
                
            }
        }
        public float buzz_motion
        {
            get
            {
                return MathHelper.SmoothStep(1.0f, 0.01f, buzz_motion_timer / State.MAX_BUZZ_MOTION_TIME); 
            }
        }
    }

    /// <summary>
    /// Questa interfaccia definisce un gioco come uno stato e
    /// delle esplosioni appena generate (per dare feedback sulle)
    /// collisioni "importanti". Potrebbe essere che ci aggiungiamo
    /// uno score, che ereditiamo State, che ereditiamo IStateProvider,
    /// etc.
    /// </summary>
    public interface IStateProvider<T>
    {
        State CurrentState { get; }
        ArrayList<Explosion> NewExplosions { get; }
        ArrayList<ShockWave> NewShockWaves { get; }
        bool Enabled { get; set; }
        T CurrentScore { get; }
    }
}